package router

import (
	"errors"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/iris-contrib/middleware/jwt"
	"github.com/kataras/iris"
	"github.com/kataras/iris/context"
	"github.com/kataras/iris/websocket"

	"im/app"
	"im/app/controller"
	"im/dao"
	"im/model"
)

// jwt
var jwtHandler = jwt.New(jwt.Config{
	Extractor: jwt.FromParameter(app.GET_NAME_OF_JWT_TOKEN),
	ValidationKeyGetter: func(token *jwt.Token) (i interface{}, e error) {
		return []byte(os.Getenv("JWT_SECRET")), nil
	},
	SigningMethod: jwt.SigningMethodHS256,
})

func WebsocketRouter(a *iris.Application) {
	// 构建服务
	events := make(websocket.Namespaces)
	events["W"] = controller.W()
	websocket.EnableDebug(os.Stdout)
	websocketServer := websocket.New(websocket.DefaultGobwasUpgrader, events)

	// 连接升级失败
	websocketServer.OnUpgradeError = func(err error) {
		log.Printf("ERROR: %v", err)
	}

	// 连接状态
	websocketServer.OnConnect = func(c *websocket.Conn) error {
		if strings.HasPrefix(c.ID(), ",e,") {
			return errors.New("令牌无效")
		}

		if c.WasReconnected() {
			log.Printf("[%s] connection is a result of a client-side re-connection, with tries: %d", c.ID(), c.ReconnectTries)
		}

		log.Printf("[%s] connected to the server.", c)

		// if returns non-nil error then it refuses the client to connect to the server.
		return nil
	}

	websocketServer.OnDisconnect = func(c *websocket.Conn) {
		log.Printf("[%s] disconnected from the server.", c)
	}

	// 启动服务,定义id生成规则,将用户信息存储至连接
	websocketRouter := a.Get("/websocket/echo", websocket.Handler(websocketServer, func(ctx context.Context) string {
		jwtStr := ctx.Values().Get("jwt")
		if jwtStr == nil {
			return websocket.DefaultIDGenerator(ctx)
		}
		loginUser := ctx.Values().Get("user").(model.Users)
		return strconv.FormatInt(loginUser.Id, 10)
	}))
	websocketRouter.Use(func(ctx context.Context) {
		if ctx.URLParamDefault("im", "") == "darcyaf" || ctx.URLParamExists("userId") {
			user := dao.NewUsersDao().Info(int64(ctx.URLParamInt64Default("userId", 0)))
			ctx.Values().Set("user", *user)
			ctx.Next()
			return
		}
		if err := handleJwt(ctx); err != nil {
			return
		}
		ctx.Next()
	})
}

func handleJwt(ctx context.Context) error {
	if err := jwtHandler.CheckJWT(ctx); err != nil {
		jwtHandler.Config.ErrorHandler(ctx, err)
		return err
	}
	parseJwtToCtx(ctx)
	return nil
}
func parseJwtToCtx(ctx context.Context) {
	jwtStr := ctx.Values().Get("jwt")
	user := jwtStr.(*jwt.Token).Claims.(jwt.MapClaims)
	loginUser := new(model.Users)
	loginUser.Id = int64(user["id"].(float64))
	loginUser.AppsId = uint(user["apps_id"].(float64))
	loginUser.Account = user["account"].(string)
	loginUser.Nickname = user["nickname"].(string)
	ctx.Values().Set("user", *loginUser)
}
